package com.cheney.common.mybatisplus.filter;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.update.Update;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 重写租户拦截器（基于mybatisPlus-3.4.1）
 *
 * @author si.chen
 * @date 2020/12/24 14:08
 */
@Component
public class MyTenantLineInnerInterceptor extends TenantLineInnerInterceptor {

    public MyTenantLineInnerInterceptor() {
    }

    public MyTenantLineInnerInterceptor(TenantLineHandler tenantLineHandler) {
        super(tenantLineHandler);
    }

    @Override
    protected void processInsert(Insert insert, int index, String sql, Object obj) {
        //---------------------
        //租户all的不处理
        if (tenantIsSuper()) {
            return;
        }
        //------------------------
        if (super.getTenantLineHandler().ignoreTable(insert.getTable().getName())) {
            // 过滤退出执行
            return;
        }
        List<Column> columns = insert.getColumns();
        if (CollectionUtils.isEmpty(columns)) {
            // 针对不给列名的insert 不处理
            return;
        }
        String tenantIdColumn = super.getTenantLineHandler().getTenantIdColumn();
        if (columns.stream().map(Column::getColumnName).anyMatch(i -> i.equals(tenantIdColumn))) {
            // 针对已给出租户列的insert 不处理
            return;
        }
        columns.add(new Column(super.getTenantLineHandler().getTenantIdColumn()));
        Select select = insert.getSelect();
        if (select != null) {
            this.processInsertSelect(select.getSelectBody());
        } else if (insert.getItemsList() != null) {
            // fixed github pull/295
            ItemsList itemsList = insert.getItemsList();
            if (itemsList instanceof MultiExpressionList) {
                ((MultiExpressionList) itemsList).getExprList().forEach(el -> el.getExpressions().add(super.getTenantLineHandler().getTenantId()));
            } else {
                ((ExpressionList) itemsList).getExpressions().add(super.getTenantLineHandler().getTenantId());
            }
        } else {
            throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId");
        }
    }

    @Override
    protected void processPlainSelect(PlainSelect plainSelect) {
        FromItem fromItem = plainSelect.getFromItem();
        Expression where = plainSelect.getWhere();
        processWhereSubSelect(where);
        if (fromItem instanceof Table) {
            Table fromTable = (Table) fromItem;
            if (!super.getTenantLineHandler().ignoreTable(fromTable.getName())) {
                //#1186 github
                //---------------------
                //租户all的不处理
                if (!tenantIsSuper()) {
                    plainSelect.setWhere(builderExpression(where, fromTable));
                }
                //------------------------
            }
        } else {
            processFromItem(fromItem);
        }
        List<Join> joins = plainSelect.getJoins();
        if (joins != null && joins.size() > 0) {
            joins.forEach(j -> {
                processJoin(j);
                processFromItem(j.getRightItem());
            });
        }
    }

    @Override
    protected void processJoin(Join join) {
        if (join.getRightItem() instanceof Table) {
            Table fromTable = (Table) join.getRightItem();
            if (super.getTenantLineHandler().ignoreTable(fromTable.getName())) {
                // 过滤退出执行
                return;
            }
            //---------------------
            //租户all的不处理
            if (tenantIsSuper()) {
                return;
            }
            //------------------------
            join.setOnExpression(builderExpression(join.getOnExpression(), fromTable));
        }
    }

    @Override
    protected void processUpdate(Update update, int index, String sql, Object obj) {
        //---------------------
        //租户all的不处理
        if (tenantIsSuper()) {
            return;
        }
        //------------------------
        final Table table = update.getTable();
        if (super.getTenantLineHandler().ignoreTable(table.getName())) {
            // 过滤退出执行
            return;
        }
        update.setWhere(this.andExpression(table, update.getWhere()));
    }

    @Override
    protected void processDelete(Delete delete, int index, String sql, Object obj) {
        //---------------------
        //租户all的不处理
        if (tenantIsSuper()) {
            return;
        }
        //------------------------
        if (super.getTenantLineHandler().ignoreTable(delete.getTable().getName())) {
            // 过滤退出执行
            return;
        }
        delete.setWhere(this.andExpression(delete.getTable(), delete.getWhere()));
    }

    /**
     * 租户为all的时候放行
     */
    private boolean tenantIsSuper() {
        return StrUtil.equals("'all'", super.getTenantLineHandler().getTenantId() + "");
    }
}
